/** here include all functions for different judgments of a gogame **/
/** 这个类涉及的算法应该在时间和空间上尽量的优化 **/

#ifndef JUDGMENT_H
#define JUDGMENT_H

//************************************************
#include "go.h"
//************************************************

/** 这套数据只针对19路棋盘设定 **/
#define D 4 //辐射模型函数的影响距离
#define BOUND 5.65 //基于辐射模型静态局面判定而设定的封闭边界值, 11.3正好是邻子的影响值, 有一定的意义
                  /** 实测修改中 **/

class Judgment
{
public:
    Judgment();
    ~Judgment();

/** Interface **/
public: //应该注意每次调用接口时候对成员变量的重置工作
    /* 默认在双方同意最终结果并且在清除死子收完所有官子(包括单官)的前提下, 计算结果才是正确的 */
    //数子法Chinese rule, return (moyoBlack,moyoWhite)
    pair<int,int> moyoCalculateCHN(int eog_board[][DIMENSION]);
    //在辐射函数判断基础上进行的数子, 相当于形势判断功能
    pair<int,int> moyoCalculateINFLUENCE(const int temp_board[][DIMENSION]); //结果初步可以满意

    // io_text_board
    // 用制表符输出的棋局图形
    // ┼, ●, ○, ┬, ┴, ├, ┤, ┌, └, ┐, ┘
    void txtBoard_printf(const int temp_board[][DIMENSION]);
    bool txtBoard_fprintf(const int temp_board[][DIMENSION], const char* fileName);

    //testing function
    bool test();

public:
    int board[DIMENSION][DIMENSION];

private:
    inline void init(int funcNum); //initialization all member variables for a certain interface-function
                            /** only used in Interface Functions **/
    inline void copyBoard(const int temp_board[][DIMENSION]); //copy parameter 2D-Array to member variable board[][]
    int getVoidBlock(int,int); //recursive function to get a block of void positions
                               //positiv return value means moyo of BLACK
                               //negativ return value means moyo of WHITE
    void init_getVoidBlock(int,int); //addtional some init-operation after recursive function

    /** io_board **/
    // 二维数组的结构:
    // 1.) 是一个指针数组，存储的是每一行的起始地址，这也就是为什么在a[N][M]中，a[j]是一个指针而不是a[j][0]数据的原因
    // 2.) 是真正的M×N的连续数据块，这解释了为什么一个二维数组可以象一维数组那样寻址的原因
    bool writeBoard(const int o_board[][DIMENSION], const char* fileName);
    bool readBoard(int i_board[][DIMENSION], const char* fileName);

    /** Algorithms **/
    //辐射函数模型
    float getInfluenceValue(int delta_x, int delta_y);
    void singleInfluence(int color, int x, int y);
    inline float getInfluenceCoefficient(int x, int y); //盘面上取决于位置的不同对辐射值加权
                                                 //第三线上系数为1, 往边缘逐次-0.2, 往中心逐次+0.1
                                                 //这个系数使得AI偏向于3,4线着子, 而非天马行空

    //辐射模型函数静态盘面计算函数
    void influenceCalculate(const int temp_board[][DIMENSION]);

    //基于辐射模型的形势判断, 目标是可以区别很明显的死棋
    //基于这样一个规则: 如果棋块本身值相反并且其有气处的值都属于对方, 那么判定棋块为死棋
    //具体BOUND的取值以及应用(判断)应该保持一致性
    void judgment_influenceCalc(int temp_board[][DIMENSION]);

    //获得棋串的函数
    void getBlock(int x, int y);
    void init_getBlock(int x, int y);

    //判断空位为单官并且将单官还原为无目数空位的函数
    void identifyPublic(const int original_board[][DIMENSION]);

    //2.) 获得棋块气数
    //3.) 判断棋块死活
    //4.) 眼的定义以及两真眼活棋的定义
    //5.) 在1,2,3,4的基础上进行形势判断(对外的接口)

private:
    bool on_off;
    int belongsTo; //被计算的空白区域的归属 可以是BLACK WHITE VOID GRID
    int moyoBlack,moyoWhite; //record moyos of BLACK&WHITE
    int count[DIMENSION][DIMENSION]; //防止重复递归
    int checked[DIMENSION][DIMENSION]; //未检查的空位的数组表示 0表示未检查的
    series tempSeries; //存放零时的棋串

    float influence[DIMENSION][DIMENSION];
};

#endif // JUDGMENT_H
